/*- Coding With UTF-8 -*/

#include "shell.h"
#include "string.h"
#include "stdio.h"

#ifdef AW_SHELL
#include "user.h"

extern SHELL_CommandTypeDef shellCmdStructArray[SHELL_CMD_LIST_COUNT];

static SHELL_TypeDef shell =
{
    .commandLength = 0,
#if SHELL_ALLOW_SHIFT == 1
    .commandCursor = 0,
#endif
#if SHELL_USE_HISTORY == 1
    .historyCount = 0,
    .historyFlag = 0,
    .historyOffset = 0,
#endif
};


/*******************************************************************************
*@function  shellReceiveByte
*@brief     shell鎺ユ敹涓�涓瓧绗�
*@param     None
*@retval    None
*@author    Letter
*@note      榛樿浣跨敤涓插彛锛屽彲閲嶅啓姝ゅ嚱鏁拌嚜瀹氫箟shell杈撳叆(鏌愪簺鎯呭喌涓�(姣斿浣跨敤涓插彛
*           涓柇璋冪敤shell)鍙互涓嶅疄鐜版鍑芥暟)
*******************************************************************************/
uint8_t shellReceiveByte(void)
{
    uint8_t recvData = 0;

//    HAL_UART_Receive(&shellUart, &recvData, 1, 100);
    recvData = (uint8_t)(shellUart.Instance->RDR & (uint8_t)0x00FF);

    return recvData;
}

/*******************************************************************************
*@function  shellDisplayByte
*@brief     shell鏄剧ず涓�涓瓧绗�
*@param     data    闇�瑕佹樉绀虹殑瀛楃
*@retval    None
*@author    Letter
*@note      榛樿浣跨敤涓插彛锛屽彲閲嶅啓姝ゅ嚱鏁拌嚜瀹氫箟shell杈撳嚭
*******************************************************************************/
void shellDisplayByte(uint8_t data)
{
//    USART_SendData(shellUart, &data, 1);
    HAL_UART_Transmit(&shellUart, &data, 1, 100);
}

/*******************************************************************************
*@function  _ShellDisplay
*@brief     shell鏄剧ず瀛楃涓�
*@param     *string    闇�瑕佹樉绀虹殑瀛楃涓叉寚閽�
*@retval    瀛楃涓查暱搴�
*@author    Letter
*@note      寤鸿浣跨敤瀹弒hellDisplay
*******************************************************************************/
uint16_t shellDisplay(const char* string)
{
//    uint16_t count = 0;
//
//    while (*string != '\0')
//    {
//        HAL_UART_Transmit(&shellUart, string, 1, 100);
//        string++;
//        count++;
//    }

    HAL_UART_Transmit(&shellUart, string, strlen(string), 100);

    return strlen(string);
}


/*******************************************************************************
*@function  shellInit
*@brief     shell鍒濆鍖�
*@param     None
*@retval    None
*@author    Letter
*******************************************************************************/
void shellInit(void)
{
#if SHELL_MODE==SHELL_MODE_TERMINAL	
	shellDisplay("\r\n");
    shellDisplay("+=========================================================+\r\n");
    shellDisplay("| (C)2016-2026 AlwhalesTech Co.,Ltd. All rights Reserved. |\r\n");
    shellDisplay("|                   Alwhales Shell "SHELL_VERSION"        |\r\n");
    shellDisplay("|               Build: "__DATE__" "__TIME__"              |\r\n");
    shellDisplay("+=========================================================+\r\n");
    shellDisplay(SHELL_COMMAND);
#else
	shellDisplay("shell ready\r\n");
#endif

//#if SHELL_USE_PARAMETER == 1
    for (uint8_t i = 0; i < SHELL_PARAMETER_MAX_NUMBER; i++)
    {
        shell.commandPointer[i] = shell.commandPara[i];
    }
//#endif

//    extern const uint32_t shellCommand$$Base;
//    extern const uint32_t shellCommand$$Limit;
//
//    shell.commandBase = (SHELL_CommandTypeDef *)(&shellCommand$$Base);
//    shell.commandLimit = (SHELL_CommandTypeDef *)(&shellCommand$$Limit);
}


/*******************************************************************************
*@function  shellMain
*@brief     shell涓诲嚱鏁�
*@param     None
*@retval    None
*@author    Letter
*@note      姝ゅ嚱鏁颁负闃诲寮忥紝閫傜敤浜嶤PU涓�鐩村浜庡伐浣滃湪shell鐨勬儏鍐碉紝鍙敱shell璋冪敤
*           澶栭儴鍑芥暟璺冲嚭
*******************************************************************************/
void shellMain(void)
{
    uint8_t receiveData;

    shellInit();

    while (1)
    {
        receiveData = shellReceiveByte();
        shellHandler_byte(receiveData);
    }
}

/*******************************************************************************
*@function  shellHandler
*@brief     shell澶勭悊鍑芥暟
*@param     receiveData     鎺ユ敹鍒扮殑鏁版嵁
*@retval    None
*@author    Letter
*@note      姝ゅ嚱鏁拌shellMain鍑芥暟璋冪敤锛岃嫢浣跨敤shellMain闃诲寮忚繍琛宻hell锛岀洿鎺ヨ皟鐢�
*           shellMain鍑芥暟鍗冲彲锛屼絾涓嶅缓璁繖鏍峰仛锛屽缓璁湪鏃犳搷浣滅郴缁熸儏鍐典笅锛屽湪shell
*           杈撳叆瑙﹀彂鐨勪腑鏂腑璋冪敤姝ゅ嚱鏁帮紙閫氬父涓轰覆鍙ｄ腑鏂級锛屾鏃舵棤闇�璋冪敤shellMain锛�
*           shell涔熶负闈為樆濉炲紡锛屾搷浣滅郴缁熸儏鍐典笅锛岄�氬父灏嗘鍑芥暟浜ょ粰shell杈撳叆璁惧鐨�
*           浠诲姟澶勭悊
*******************************************************************************/
#if SHELL_MODE==SHELL_MODE_TERMINAL
void shellHandler(uint8_t receiveData)
{
    static uint8_t runFlag=0;
//	  static uint8_t endFlag=0;
    static CONTROL_Status controlFlag = CONTROL_FREE;
    switch (receiveData)
    {
    case '\r':
//			endFlag=1;
//			break;
    case '\n':
//			if(!endFlag)
//				break;
//			endFlag=0;
        if (shell.commandLength >= SHELL_COMMAND_MAX_LENGTH - 1)
        {
            shellDisplay("\r\nError: Command is too long\r\n");
            shell.commandBuff[shell.commandLength] = 0;
            shell.commandLength = 0;
#if SHELL_ALLOW_SHIFT == 1
            shell.commandCursor = 0;
#endif
            shellDisplay(SHELL_COMMAND);
            break;
        }

        if (shell.commandLength == 0)
        {
            shellDisplay(SHELL_COMMAND);
            break;
        }
        else
        {
            shell.commandBuff[shell.commandLength++] = 0;

            shell.commandCount = 0;

            uint8_t j = 0;
            for (int8_t i = 0; i < shell.commandLength; i++)
            {
                if (shell.commandBuff[i] != ' ' &&
                        shell.commandBuff[i] != '\t' &&
                        shell.commandBuff[i] != 0)
                {
                    shell.commandPara[shell.commandCount][j++] = shell.commandBuff[i];
                }
                else
                {
                    if (j != 0)
                    {
                        shell.commandPara[shell.commandCount][j] = 0;
                        shell.commandCount ++;
                        j = 0;
                    }
                }
            }
            shell.commandLength = 0;
#if SHELL_ALLOW_SHIFT == 1
            shell.commandCursor = 0;
#endif

            if (shell.commandCount == 0)                      //鏄惁涓烘棤鏁堟寚浠�
            {
                shellDisplay(SHELL_COMMAND);
                break;
            }

#if SHELL_USE_HISTORY == 1
            shellStringCopy(shell.historyCommand[shell.historyFlag++],
                            shell.commandBuff);
            if (++shell.historyCount > SHELL_HISTORY_MAX_NUMBER)
            {
                shell.historyCount = SHELL_HISTORY_MAX_NUMBER;
            }
            if (shell.historyFlag >= SHELL_HISTORY_MAX_NUMBER)
            {
                shell.historyFlag = 0;
            }
            shell.historyOffset = 0;
#endif /* SHELL_USE_HISTORY == 1 */

            shellDisplay("\r\n");
            runFlag = 0;

            for (int8_t  i= 0;
                    i < ((uint32_t)shell.commandLimit -
                        (uint32_t)shell.commandBase) / sizeof(SHELL_CommandTypeDef);
                    i++)
            {
                if (strcmp((const char *)shell.commandPara[0],
                           (const char *)(shell.commandBase + i)->name) == 0)
                {
                    (shell.commandBase + i)->function(shell.commandCount, shell.commandPointer);
									runFlag = 1;
                    break;
                }
            }

            if (runFlag == 0)
            {
                shellDisplay("Command not found");
            }
        }
        shellDisplay(SHELL_COMMAND);
        break;

    case 0x08:                                          //閫�鏍�
        if (shell.commandLength != 0)
        {  
#if SHELL_ALLOW_SHIFT == 1
            if (shell.commandCursor == shell.commandLength)
            {
                shell.commandLength--;
                shell.commandCursor--;
                shell.commandBuff[shell.commandLength] = 0;
                shellBackspace(1);
            }
            else if (shell.commandCursor > 0)
            {
                for (int8_t i = 0;
                        i < shell.commandLength - shell.commandCursor; i++)
                {
                    shell.commandBuff[shell.commandCursor + i - 1] =
                        shell.commandBuff[shell.commandCursor + i];
                }
                shellClearLine();
                shell.commandBuff[shell.commandLength - 1] = 0;
                shellDisplay(shell.commandBuff);
                shell.commandLength --;
                shell.commandCursor --;
                for (int8_t i = shell.commandLength - shell.commandCursor;
                        i > 0; i--)
                {
                    shellDisplayByte('\b');
                }
            }
#else
            shell.commandLength--;
            shell.commandBuff[shell.commandLength] = 0;
            shellBackspace(1);
#endif /* SHELL_ALLOW_SHIFT == 1 */
        }
        break;

    case '\t':                                          //鍒惰〃绗�
        if (shell.commandLength != 0)
        {
            for (int8_t  i= 0;
                    i < ((uint32_t)shell.commandLimit -
                        (uint32_t)shell.commandBase) / sizeof(SHELL_CommandTypeDef);
                    i++)
            {
                if (strncmp((const char *)shell.commandBuff,
                            (const char *)(shell.commandBase + i)->name, shell.commandLength) == 0)
                {
#if SHELL_ALLOW_SHIFT ==1
                    shellClearLine();
#else
                    shellBackspace(shell.commandLength);
#endif /* SHELL_ALLOW_SHIFT ==1 */
                    shell.commandLength = shellStringCopy(shell.commandBuff,
                                             (shell.commandBase + i)->name);
#if SHELL_ALLOW_SHIFT == 1
                    shell.commandCursor = shell.commandLength;
#endif
                    shellDisplay(shell.commandBuff);
                }
            }
        }
        else                                            //鏃犺緭鍏ワ紝杈撳叆help
        {
            shellBackspace(shell.commandLength);
            shell.commandLength = shellStringCopy(shell.commandBuff, (uint8_t *)"help");
#if SHELL_ALLOW_SHIFT == 1
            shell.commandCursor = shell.commandLength;
#endif
            shellDisplay(shell.commandBuff);
        }
        break;

    case 0x1B:                                          //鎺у埗閿�
        controlFlag = CONTROL_STEP_ONE;
        break;

    default:
        switch ((uint8_t)controlFlag)
        {
        case CONTROL_STEP_TWO:
            if (receiveData == 0x41)                //鏂瑰悜涓婇敭
            {
#if SHELL_USE_HISTORY == 1
#if SHELL_ALLOW_SHIFT == 1
                shellClearLine();
#else
                shellBackspace(shell.commandLength);
#endif /* SHELL_ALLOW_SHIFT == 1 */
                if (shell.historyOffset--
                        <= -((shell.historyCount > shell.historyFlag)
                             ? shell.historyCount : shell.historyFlag))
                {
                    shell.historyOffset
                        = -((shell.historyCount > shell.historyFlag)
                            ? shell.historyCount : shell.historyFlag);
                }
                shell.commandLength = shellStringCopy(shell.commandBuff,
                                         shell.historyCommand[(shell.historyFlag + SHELL_HISTORY_MAX_NUMBER
                                                 + shell.historyOffset) % SHELL_HISTORY_MAX_NUMBER]);
#if SHELL_ALLOW_SHIFT == 1
                shell.commandCursor = shell.commandLength;
#endif
                shellDisplay(shell.commandBuff);
#else
                //shellDisplay("up\r\n");
#endif /* SHELL_ALLOW_SHIFT == 1 */
            }
            else if (receiveData == 0x42)           //鏂瑰悜涓嬮敭
            {
#if SHELL_USE_HISTORY == 1
                if (++shell.historyOffset >= 0)
                {
                    shell.historyOffset = -1;
                    break;
                }
#if SHELL_ALLOW_SHIFT == 1
                shellClearLine();
#else
                shellBackspace(shell.commandLength);
#endif
                shell.commandLength = shellStringCopy(shell.commandBuff,
                                         shell.historyCommand[(shell.historyFlag + SHELL_HISTORY_MAX_NUMBER
                                                 + shell.historyOffset) % SHELL_HISTORY_MAX_NUMBER]);
#if SHELL_ALLOW_SHIFT == 1
                shell.commandCursor = shell.commandLength;
#endif
                shellDisplay(shell.commandBuff);
#else
                //shellDisplay("down\r\n");
#endif /* SHELL_ALLOW_SHIFT == 1 */
            }
            else if (receiveData == 0x43)           //鏂瑰悜鍙抽敭
            {
#if SHELL_ALLOW_SHIFT == 1
                if (shell.commandCursor < shell.commandLength)
                {
                    shellDisplayByte(shell.commandBuff[shell.commandCursor]);
                    shell.commandCursor++;
                }
#endif
                //shellDisplay("right\r\n");
            }
            else if (receiveData == 0x44)           //鏂瑰悜宸﹂敭
            {
#if SHELL_ALLOW_SHIFT == 1
                if (shell.commandCursor > 0)
                {
                    shellDisplayByte('\b');
                    shell.commandCursor--;
                }
#endif
                //shellDisplay("left\r\n");
            }
            else
            {
                controlFlag = CONTROL_FREE;
                goto normal;
            }
            break;

        case CONTROL_STEP_ONE:
            if (receiveData == 0x5B)
            {
                controlFlag = CONTROL_STEP_TWO;
            }
            else
            {
                controlFlag = CONTROL_FREE;
                goto normal;
            }
            break;

        case CONTROL_FREE:                          //姝ｅ父鎸夐敭澶勭悊
normal:
            if (shell.commandLength < SHELL_COMMAND_MAX_LENGTH - 1)
            {
#if SHELL_ALLOW_SHIFT == 1
                if (shell.commandCursor == shell.commandLength)
                {
                    shell.commandBuff[shell.commandLength++] = receiveData;
                    shell.commandCursor++;              //鍏夋爣浣嶇疆鍔�1
                    shellDisplayByte(receiveData);
                }
                else
                {
                    for (int8_t i = shell.commandLength - shell.commandCursor;
                            i > 0; i--)
                    {
                        shell.commandBuff[shell.commandCursor + i] =
                            shell.commandBuff[shell.commandCursor + i - 1];
                    }
                    shellClearLine();
                    shell.commandBuff[shell.commandCursor++] = receiveData;
                    shell.commandBuff[++shell.commandLength] = 0;
                    shellDisplay(shell.commandBuff);
                    for (int8_t i = shell.commandLength - shell.commandCursor;
                            i > 0; i--)
                    {
                        shellDisplayByte('\b');
                    }
                }
#else /* SHELL_ALLOW_SHIFT == 1 */
                shell.commandBuff[shell.commandLength++] = receiveData;
                shellDisplayByte(receiveData);
#endif /* SHELL_ALLOW_SHIFT == 1 */
            }
            else
            {
#if SHELL_ALLOW_SHIFT == 1
                shellDisplay("\r\nWarnig: Command is too long\r\n");
                shellDisplay(SHELL_COMMAND);
                shellDisplay(shell.commandBuff);
                shell.commandCursor = shell.commandLength;
#else
                shell.commandLength++;
                shellDisplayByte(receiveData);
#endif /* SHELL_ALLOW_SHIFT == 1 */
            }
            break;

        }
        break;
    }
}

#else
void shellHandler_byte(uint8_t receiveByte)
{
    static uint8_t runFlag=0;
    static uint8_t endFlag=0;
		char stringBuff[50];
    switch (receiveByte)
    {
    case '\r':
			endFlag=1;
			break;
    case '\n':
			if(!endFlag)
				break;
			endFlag=0;
			/**
			 * Error code 1: Command too long.
			 */
			if(shell.commandLength >= SHELL_COMMAND_MAX_LENGTH - 1)
			{
					shellDisplay("#Err:1#\r\n");
					shell.commandBuff[shell.commandLength] = 0;
					shell.commandLength = 0;
					//shellDisplay(SHELL_COMMAND);
					break;
			}
			/**
			 * Error code 2: No command.
			 */
			if (shell.commandLength == 0)
			{
				shellDisplay("#Err:2#\r\n");
					//shellDisplay(SHELL_COMMAND);
					break;
			}
			else
			{
					shell.commandBuff[shell.commandLength++] = 0;
					shell.commandCount = 0;

					uint8_t j = 0;
					for (int8_t i = 0; i < shell.commandLength; i++)
					{
							if (shell.commandBuff[i] != ' ' &&
											shell.commandBuff[i] != '\t' &&
											shell.commandBuff[i] != 0)
							{
									shell.commandPara[shell.commandCount][j++] = shell.commandBuff[i];
							}
							else
							{
									if (j != 0)
									{
											shell.commandPara[shell.commandCount][j] = 0;
											shell.commandCount ++;
											j = 0;
									}
							}
					}
					shell.commandLength = 0;
			/**
			 * Error code 3: Command invaild.
			 */
					if (shell.commandCount == 0)                      //鏄惁涓烘棤鏁堟寚浠�
					{
							shellDisplay("#Err:3#\r\n");
							break;
					}

					runFlag = 0;

					for (int8_t  i= 0;i<sizeof(shellCmdStructArray)/sizeof(*shellCmdStructArray);i++)
					{
							if (strcmp((const char *)shell.commandPara[0],shellCmdStructArray[i].name) == 0)
							{               
								int res = shellCmdStructArray[i].function(shell.commandCount, shell.commandPointer);
								runFlag = 1;
								sprintf(stringBuff,"#OK:%d#\r\n",res);
								shellDisplay(stringBuff);
								break;
							}
					}
/**
 * Error code 4: Command not found.
 */
					if (runFlag == 0)
					{
							shellDisplay("#Err:4#\r\n");
					}
			}
			//shellDisplay(SHELL_COMMAND);
			break;
				
		default:
            if (shell.commandLength < SHELL_COMMAND_MAX_LENGTH - 1)
            {
                shell.commandBuff[shell.commandLength++] = receiveByte;
                //shellDisplayByte(receiveData);
            }
            else
            {
                shell.commandLength++;
                //shellDisplayByte(receiveData);
            }
            break;
        }
}

uint16_t shellHandler_string(char *receiveString)
{
	uint16_t count = 0;

    while (*receiveString)
    {
    	shellHandler_byte(*(receiveString++));
        count++;
    }

    return count;
}

#endif
/*******************************************************************************
*@function  shellStringCopy
*@brief     瀛楃涓插鍒�
*@param     *dest       鐩爣瀛楃涓�
*           *src        婧愬瓧绗︿覆
*@retval    瀛楃涓查暱搴�
*@author    Letter
*******************************************************************************/
uint8_t shellStringCopy(uint8_t *dest, uint8_t *src)
{
    uint8_t count = 0;
    while (*src)
    {
        *(dest++) = *(src++);
        count++;
    }
    *dest = 0;
    return count;
}


/*******************************************************************************
*@function  shellBackspace
*@brief     鍛戒护琛岄��鏍兼搷浣�
*@param     length      閫�鏍奸暱搴�
*@retval    None
*@author    Letter
*******************************************************************************/
void shellBackspace(uint8_t length)
{
    while (length--)
    {
        shellDisplayByte(0x08);                             //"\b \b"
        shellDisplayByte(' ');
        shellDisplayByte(0x08);
    }
}


#if SHELL_ALLOW_SHIFT == 1
/*******************************************************************************
*@function  shellClearLine
*@brief     娓呴櫎鍛戒护琛�
*@param     None
*@retval    None
*@author    Letter
*******************************************************************************/
void shellClearLine(void)
{
    for (int8_t i = shell.commandLength - shell.commandCursor; i > 0; i--)
    {
        shellDisplayByte(' ');
    }
    shellBackspace(shell.commandLength);
}
#endif

//int atoi(char s[])  
//{  
//    int i;  
//    int n = 0;  
//    for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i)  
//    {  
//        n = 10 * n + (s[i] - '0');  
//    }  
//    return n;  
//}  
#endif
